package cz.ctu.guiproject.client.manager;

import static cz.ctu.guiproject.client.resources.constants.Constants.ACTIVITY_ELEMENT;
import static cz.ctu.guiproject.client.resources.constants.Logger.TAG;

import java.io.IOException;
import java.io.StringReader;
import java.util.Deque;
import java.util.LinkedList;
import java.util.Set;
import java.util.TreeSet;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

import android.app.Activity;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import cz.ctu.guiproject.client.R;
import cz.ctu.guiproject.client.messaging.ForceUIUpdate;
import cz.ctu.guiproject.client.resources.ActivityProvider;
import cz.ctu.guiproject.client.xml.XmlDecodeFactory;

public final class UIManagerImpl implements UIManager {

	// private final Dispatcher dispatcher;
	private JARManager jarManager;
	private Activity activity;

	public UIManagerImpl() {
		jarManager = JARManagerImpl.getInstance();
		activity = ActivityProvider.getInstance().getActivity();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see cz.ctu.guiproject.client.manager.UIManager#initUI(java.lang.String)
	 */
	@Override
	public boolean initUI(String xml) {
		// call JARManager to get all Views with assigned events and ViewGroups
		decodeInitialLayout(xml);

		Log.i(TAG, "initUI implementation called!");
		return true;
	}

	private void decodeInitialLayout(String xml) {
		final SAXParserFactory factory = SAXParserFactory.newInstance();
		final DefaultHandler handler = new InitialLayoutHandler();
		try {
			final SAXParser saxParser = factory.newSAXParser();
			saxParser.parse(new InputSource(new StringReader(xml)), handler);
		} catch (ParserConfigurationException e) {
			Log.e(TAG, e.getMessage());
		} catch (SAXException e) {
			Log.e(TAG, e.getMessage());
		} catch (IOException e) {
			Log.e(TAG, e.getMessage());
		}
	}

	private class InitialLayoutHandler extends DefaultHandler {

		private Deque<ViewGroup> vgStack;
		private Set<String> vgContain;

		InitialLayoutHandler() {
			vgStack = new LinkedList<ViewGroup>();
			vgContain = new TreeSet<String>();
		}

		@Override
		public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
			if(qName.equals(ACTIVITY_ELEMENT)) {
				// pass current Activity object and Context to JARManager and enrich current activity with new attributes
				// just works as a setter, we already have Activity
				jarManager.setActivity(qName, attributes);
				return;
			}
			// send to JARManager, whether entity of that name exists
			final View view = jarManager.getView(qName, attributes);
			if (view == null) {
				// view nenalezeno
				Log.i(TAG, "Corresponding View " + qName + " not found.");
			} else {
				final ViewGroup viewGroup;
				if (vgStack.isEmpty()) {
					viewGroup = null;
				} else {
					// get the head, not remove
					viewGroup = vgStack.peek();
				}
				if (view instanceof ViewGroup) {
					// first ViewGroup
					if (vgStack.isEmpty()) {
						// add ViewGroup to initialLayout
						activity.runOnUiThread(new Runnable() {
							@Override
							public void run() {
								LinearLayout layout = (LinearLayout) activity.findViewById(R.id.initialLayout);
								layout.addView(view);
							}
						});
					} else {
						activity.runOnUiThread(new Runnable() {
							@Override
							public void run() {
								viewGroup.addView(view);
							}
						});
					}
					vgStack.push((ViewGroup) view);
					vgContain.add(qName);
				} else {
					activity.runOnUiThread(new Runnable() {
						@Override
						public void run() {
							viewGroup.addView(view);
						}
					});
				}
			}
		}

		@Override
		public void endElement(String uri, String localName, String qName) throws SAXException {
			if (vgContain.contains(qName)) {
				// get the head and remove it
				vgStack.pop();
			}
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * cz.ctu.guiproject.client.manager.UIManager#forceUIUpdate(java.lang.String
	 * )
	 */
	@Override
	public void forceUIUpdate(String xml) {
		final ForceUIUpdate forceUIUpdate = XmlDecodeFactory.decodeForceUIUpdate(xml);
		jarManager.setViewAttribute(forceUIUpdate.getViewId(), forceUIUpdate.getAttrName(),
				forceUIUpdate.getAttrValue());

		Log.i(TAG, "forceUIUpdate implementation called!");
	}
}
